#include <func.h>

int main(int argc, char *argv[])
{
    ARGS_CHECK(argc, 3);

    // 1. 生成套接字描述符
    int sfd = socket(AF_INET, SOCK_STREAM, 0);

    
    struct sockaddr_in ser_addr; // 服务器信息结构体
    bzero(&ser_addr, sizeof(ser_addr));
    ser_addr.sin_family = AF_INET; // 使用IPv4
    ser_addr.sin_port = htons(atoi(argv[2])); // 端口号
    ser_addr.sin_addr.s_addr = inet_addr(argv[1]); // IP地址

    // 2. bind
    int ret = bind(sfd, (struct sockaddr *)&ser_addr, sizeof(ser_addr));
    ERROR_CHECK(ret, -1, "bind");

    // 3. listen
    ret = listen(sfd, 10);

    // 4. accept 进行三次握手
    struct sockaddr_in client_addr; // 客户端信息结构体
    bzero(&client_addr, sizeof(client_addr));
    int addr_len = sizeof(client_addr);
    

    // 实现客户端断开后可重连
    int new_fd;
    fd_set rdset, tmpset; // tmpset做传入传出参数，rdset添加或移除client
    FD_ZERO(&rdset);
    FD_SET(sfd, &rdset);
    FD_SET(STDIN_FILENO, &rdset);
    char buf[128] = {0};
    while (1)
    {
        memcpy(&tmpset, &rdset, sizeof(fd_set));

        select(11, &tmpset, NULL, NULL, NULL);

        // 来了新client
        if (FD_ISSET(sfd, &tmpset))
        {
            new_fd = accept(sfd, (struct sockaddr *)&client_addr, &addr_len);
            ERROR_CHECK(new_fd, -1, "accept");
            printf("client %s %d success connect\n", inet_ntoa(client_addr.sin_addr), ntohs(client_addr.sin_port));
            FD_SET(new_fd, &rdset); // 把新的client加入到监控集合中
        }

        // 可发
        if (FD_ISSET(STDIN_FILENO, &tmpset))
        {
            bzero(buf, sizeof(buf));
            read(STDIN_FILENO, buf, sizeof(buf));
            send(new_fd, buf, strlen(buf) - 1, 0);
        }

        // 可收
        if (FD_ISSET(new_fd, &tmpset))
        {
            bzero(buf, sizeof(buf));
            ret = recv(new_fd, buf, sizeof(buf), 0);
            if (!ret) 
            {
                printf("The other side break the chat\b");
                FD_CLR(new_fd, &rdset); // 将这个client从监控集合中移除
            }
            else
            {
                printf("%s\n", buf);
            }
        }
    }

    close(sfd);
    close(new_fd);
    return 0;
}
